using Microsoft.AspNetCore.Mvc;
using ErrorCode;
using Microsoft.Extensions.Logging;
using System;
using System.Text;
using Microsoft.Extensions.Caching.Memory;
using SkiaSharp;
using System.IO;
using RabbitTraceability.Api.Dtos.Request;
using RabbitTraceability.Api.Dtos.Response;
using Infrastructure.Redis;

namespace RabbitTraceability.Api.Controllers
{
    /// <summary>
    /// 验证码控制器
    /// </summary>
    [ApiController]
    [Route("api/[controller]/[action]")]
    public class CaptchaController : ControllerBase
    {
        private readonly ILogger<CaptchaController> _logger;
        private readonly IMemoryCache _cache;
        private readonly IRedisHelper _redisHelper;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        /// <param name="cache">内存缓存</param>
        public CaptchaController(ILogger<CaptchaController> logger, IMemoryCache cache, IRedisHelper redisHelper)
        {
            _logger = logger;
            _cache = cache;
            _redisHelper = redisHelper;
        }

        /// <summary>
        /// 生成图片验证码（返回图片文件）
        /// </summary>
        /// <param name="guid">客户端传入的GUID，如果为空则自动生成</param>
        /// <param name="width">图片宽度，默认120</param>
        /// <param name="height">图片高度，默认40</param>
        /// <returns>验证码图片文件</returns>
        [HttpGet("image")]
        public  IActionResult GenerateImage([FromQuery] string? guid = null, [FromQuery] int width = 120, [FromQuery] int height = 40)
        {
            try
            {
                // 如果前端没有传入GUID，则生成一个新的GUID
                var captchaGuid = string.IsNullOrWhiteSpace(guid) ? Guid.NewGuid().ToString() : guid;

                // 生成验证码
                var captchaCode = GenerateCaptchaCode();

                // 生成验证码图片字节数组
                var imageBytes = GenerateCaptchaImageBytes(captchaCode, width, height);

                // 将验证码存储到缓存中，设置5分钟过期时间
                var cacheKey = $"captcha_{captchaGuid}";
                _cache.Set(cacheKey, captchaCode, TimeSpan.FromMinutes(5));

                _logger.LogInformation("生成图片验证码成功，GUID: {Guid}, 验证码: {Code}", captchaGuid, captchaCode);

                // 在响应头中返回GUID
                Response.Headers.Add("X-Captcha-Guid", captchaGuid);
                Response.Headers.Add("X-Captcha-Expires-In", "300");
                // 使用String分组存储验证码，过期时间设置为10秒
                string redisKey = $"Captcha:String:{captchaGuid}";
                _redisHelper.SetStringAsync(redisKey, captchaCode, TimeSpan.FromSeconds(120));
                return  File(imageBytes, "image/png");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "生成验证码图片时发生错误");
                return BadRequest("验证码生成失败");
            }
        }

        /// <summary>
        /// 验证验证码
        /// </summary>
        /// <param name="request">验证请求</param>
        /// <returns>验证结果</returns>
        [HttpPost]
        public ApiResult<bool> Verify([FromBody] VerifyCaptchaRequestDto request)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(request.Guid) || string.IsNullOrWhiteSpace(request.Code))
                {
                    return ApiResult<bool>.Fail("GUID和验证码不能为空", ResultCode.参数错误);
                }

                var cacheKey = $"captcha_{request.Guid}";

                // 从缓存中获取验证码
                if (_cache.TryGetValue(cacheKey, out string? cachedCode))
                {
                    // 验证码不区分大小写
                    var isValid = string.Equals(cachedCode, request.Code, StringComparison.OrdinalIgnoreCase);

                    if (isValid)
                    {
                        // 验证成功后删除缓存中的验证码（一次性使用）
                        _cache.Remove(cacheKey);
                        _logger.LogInformation("验证码验证成功，GUID: {Guid}", request.Guid);
                        return ApiResult<bool>.SuccessWithData(true, "验证码验证成功");
                    }
                    else
                    {
                        _logger.LogWarning("验证码验证失败，输入错误，GUID: {Guid}", request.Guid);
                        return ApiResult<bool>.Fail("验证码错误", ResultCode.操作失败);
                    }
                }
                else
                {
                    _logger.LogWarning("验证码已过期或不存在，GUID: {Guid}", request.Guid);
                    return ApiResult<bool>.Fail("验证码已过期或不存在", ResultCode.操作失败);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "验证验证码时发生错误，GUID: {Guid}", request.Guid);
                return ApiResult<bool>.Fail("验证码验证失败", ResultCode.服务器错误);
            }
        }

        /// <summary>
        /// 生成随机验证码
        /// </summary>
        /// <param name="length">验证码长度，默认4位</param>
        /// <returns>验证码字符串</returns>
        private static string GenerateCaptchaCode(int length = 4)
        {
            // 可选字符集（排除容易混淆的字符如0、O、1、I、l等）
            const string chars = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
            var random = new Random();
            var result = new StringBuilder(length);

            for (int i = 0; i < length; i++)
            {
                result.Append(chars[random.Next(chars.Length)]);
            }

            return result.ToString();
        }

        /// <summary>
        /// 生成验证码图片
        /// </summary>
        /// <param name="code">验证码文本</param>
        /// <param name="width">图片宽度</param>
        /// <param name="height">图片高度</param>
        /// <returns>Base64编码的图片数据</returns>
        private static string GenerateCaptchaImage(string code, int width, int height)
        {
            using var surface = SKSurface.Create(new SKImageInfo(width, height));
            var canvas = surface.Canvas;
            var random = new Random();

            // 设置背景色（浅灰色）
            canvas.Clear(SKColors.White);

            // 创建画笔
            using var paint = new SKPaint
            {
                Color = SKColors.Black,
                TextSize = height * 0.6f,
                IsAntialias = true,
                Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold)
            };

            // 绘制干扰线
            using var linePaint = new SKPaint
            {
                Color = SKColors.LightGray,
                StrokeWidth = 1,
                IsAntialias = true
            };

            for (int i = 0; i < 5; i++)
            {
                var x1 = random.Next(0, width);
                var y1 = random.Next(0, height);
                var x2 = random.Next(0, width);
                var y2 = random.Next(0, height);
                canvas.DrawLine(x1, y1, x2, y2, linePaint);
            }

            // 绘制验证码字符
            var charWidth = width / code.Length;
            for (int i = 0; i < code.Length; i++)
            {
                // 随机颜色
                var colors = new[] { SKColors.Black, SKColors.Blue, SKColors.Red, SKColors.Green, SKColors.Purple };
                paint.Color = colors[random.Next(colors.Length)];

                // 计算字符位置（加入随机偏移）
                var x = charWidth * i + charWidth / 4 + random.Next(-5, 5);
                var y = height / 2 + paint.TextSize / 3 + random.Next(-5, 5);

                // 随机旋转角度
                canvas.Save();
                canvas.RotateDegrees(random.Next(-15, 15), x, y);
                canvas.DrawText(code[i].ToString(), x, y, paint);
                canvas.Restore();
            }

            // 添加噪点
            using var noisePaint = new SKPaint
            {
                Color = SKColors.Gray,
                StrokeWidth = 1
            };

            for (int i = 0; i < 100; i++)
            {
                var x = random.Next(0, width);
                var y = random.Next(0, height);
                canvas.DrawPoint(x, y, noisePaint);
            }

            // 转换为图片数据
            using var image = surface.Snapshot();
            using var data = image.Encode(SKEncodedImageFormat.Png, 90);
            return Convert.ToBase64String(data.ToArray());
        }

        /// <summary>
        /// 生成验证码图片字节数组
        /// </summary>
        /// <param name="code">验证码文本</param>
        /// <param name="width">图片宽度</param>
        /// <param name="height">图片高度</param>
        /// <returns>图片字节数组</returns>
        private static byte[] GenerateCaptchaImageBytes(string code, int width, int height)
        {
            using var surface = SKSurface.Create(new SKImageInfo(width, height));
            var canvas = surface.Canvas;
            var random = new Random();

            // 设置背景色（白色）
            canvas.Clear(SKColors.White);

            // 创建画笔
            using var paint = new SKPaint
            {
                Color = SKColors.Black,
                TextSize = height * 0.6f,
                IsAntialias = true,
                Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold)
            };

            // 绘制干扰线
            using var linePaint = new SKPaint
            {
                Color = SKColors.LightGray,
                StrokeWidth = 1,
                IsAntialias = true
            };

            for (int i = 0; i < 5; i++)
            {
                var x1 = random.Next(0, width);
                var y1 = random.Next(0, height);
                var x2 = random.Next(0, width);
                var y2 = random.Next(0, height);
                canvas.DrawLine(x1, y1, x2, y2, linePaint);
            }

            // 绘制验证码字符
            var charWidth = width / code.Length;
            for (int i = 0; i < code.Length; i++)
            {
                // 随机颜色
                var colors = new[] { SKColors.Black, SKColors.Blue, SKColors.Red, SKColors.Green, SKColors.Purple };
                paint.Color = colors[random.Next(colors.Length)];

                // 计算字符位置（加入随机偏移）
                var x = charWidth * i + charWidth / 4 + random.Next(-5, 5);
                var y = height / 2 + paint.TextSize / 3 + random.Next(-5, 5);

                // 随机旋转角度
                canvas.Save();
                canvas.RotateDegrees(random.Next(-15, 15), x, y);
                canvas.DrawText(code[i].ToString(), x, y, paint);
                canvas.Restore();
            }

            // 添加噪点
            using var noisePaint = new SKPaint
            {
                Color = SKColors.Gray,
                StrokeWidth = 1
            };

            for (int i = 0; i < 100; i++)
            {
                var x = random.Next(0, width);
                var y = random.Next(0, height);
                canvas.DrawPoint(x, y, noisePaint);
            }

            // 转换为图片字节数组
            using var image = surface.Snapshot();
            using var data = image.Encode(SKEncodedImageFormat.Png, 90);
            return data.ToArray();
        }
    }
}